package obecto.task.progress
{
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	
	import obecto.event.EventDescriptor;
	import obecto.event.TaskEvent;
	import obecto.task.BaseTask;
	import obecto.task.ITask;
	import obecto.utility.Listener;

	[Event(name="start", type="obecto.event.TaskEvent")]
	[Event(name="interrupted", type="obecto.event.TaskEvent")]
	[Event(name="complete", type="obecto.event.TaskEvent")]
	[Event(name="progress", type="flash.events.ProgressEvent")]

	/**
	 * <code>ProgressiveTaskDecorator</code> is used whenever we want to dispatch 
	 * <b><i>_progress</i></b>-events for tasks, that don't implement 
	 * <code>IProgressiveTask</code>. <code>ProgressiveTaskDecorator</code> wraps an 
	 * <code>ITask</code> and dispatches a fake _progress for it.
	 */
	public class FakeProgressDispatcher extends BaseTask implements IProgressiveTask
	{
		private static const DEFAULT_FAKE_PROGRESS_DISPATCH_INTERVAL : int = 100;
		private static const DEFAULT_FAKE_PROGRESS_DISPATCH_PERCENTS : Number = 10;
	
		public var autoStart : Boolean = true;
		public var autoComplete : Boolean = true;
		
		protected var _monitoredTask : ITask;
		public function set monitoredTask(value : ITask) : void
		{
			if(_monitoredTask != value)
			{
				_monitoredTask = value;
				
				removeListeners();

				if(_monitoredTask != null)
				{
					startListener = Listener.create(_monitoredTask, TaskEvent.START,
						handleMonitoredTaskStart, null, false, true);
	
					completeListener = Listener.create(_monitoredTask, TaskEvent.COMPLETE,
						handleMonitoredTaskComplete, null, false, true);
						
					interuptListener = Listener.create(_monitoredTask, TaskEvent.INTERRUPT,
						handleMonitoredTaskInterupt, null, false, true);
				}
			}
		}
		public function get monitoredTask() : ITask
		{
			return _monitoredTask;
		}
		
		protected var startListener : Listener;
		protected var completeListener : Listener;
		protected var interuptListener : Listener;
		
		protected var _progress : Number = 0;
		
		public function get progress() : Number 
		{
			return _progress;
		}
		
		private var timer : Timer;
		
		private var _fakeProgressDispatchInterval : int = 0;
		public function get fakeProgressDispatchInterval() : int 
		{ 
			return _fakeProgressDispatchInterval; 
		}		
		public function set fakeProgressDispatchInterval(value:int) : void 
		{ 
			_fakeProgressDispatchInterval = value;
			
			if(timer)
			{
				timer.delay = _fakeProgressDispatchInterval;
			} 
		}
	
		public var fakeProgressDispatchPercents : Number;
		
		public function FakeProgressDispatcher(aTask:ITask=null, fakeProgressDispatchInterval:int = 0, fakeProgressDispatchPercents:Number = 0)
		{
			super();
			
			if(fakeProgressDispatchInterval > 0)
			{
				this.fakeProgressDispatchInterval = fakeProgressDispatchInterval;
			}
			else
			{
				this.fakeProgressDispatchInterval = DEFAULT_FAKE_PROGRESS_DISPATCH_INTERVAL;
			}
			
			if(fakeProgressDispatchPercents > 0)
			{
				this.fakeProgressDispatchPercents = fakeProgressDispatchPercents;
			}
			else
			{
				this.fakeProgressDispatchPercents = DEFAULT_FAKE_PROGRESS_DISPATCH_PERCENTS;
			}
			
			monitoredTask = aTask;
		}
		
		public function forceComplete() : void 
		{
			complete();
		}
	
		override protected function startActual() : void 
		{
			_progress = 0;

			timer = new Timer(fakeProgressDispatchInterval);
			timer.addEventListener(TimerEvent.TIMER, handleTimerElapsed, false, 0, true);
			timer.start();		
		}
		
		override protected function complete() : void 
		{
			dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, 100, 100));
			
			removeListeners();			
			stopTimer();
			
			super.complete();
		}
	
		private function handleTimerElapsed(aEvent : Event) : void 
		{
			_progress += fakeProgressDispatchPercents;
			
			if(_progress < 100)
			{
				dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _progress, 100));
			}
			else
			{
				if(!_monitoredTask && autoComplete)
				{
					complete();
				}
				else
				{
					stopTimer();
				}
			}
		}

		protected function handleMonitoredTaskStart(event : TaskEvent) : void
		{
			if(!_running && autoStart)
			{
				start();
			}
		}
				
		protected function handleMonitoredTaskComplete(event : TaskEvent) : void
		{
			if(_running)
			{
				complete();
			}
		}
		
		protected function handleMonitoredTaskInterupt(event : TaskEvent) : void
		{
			if(_running)
			{
				stopTimer();
			}
		}
		
		protected function stopTimer() : void
		{
			timer.removeEventListener(TimerEvent.TIMER, handleTimerElapsed);
			timer.stop();
			timer = null;
		}
		
		protected function removeListeners() : void
		{
			if(startListener != null && startListener.listening)
			{
				startListener.stop();
				startListener = null;
			}
			
			if(completeListener != null && completeListener.listening)
			{
				completeListener.stop();
				completeListener = null;
			}
			
			if(interuptListener != null && interuptListener.listening)
			{
				interuptListener.stop();
				interuptListener = null;
			}
		}
	}
}